using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace DeSleeper.Client.Framework
{
    public class DelegateCommand : ICommand
    {
        private Action<object> _executeMethod;

        public DelegateCommand(Action<object> executeMethod)
        {
            _executeMethod = executeMethod;
        }

        public void Execute(object parameter)
        {
            _executeMethod(parameter);
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;
    }

    public class AsyncDelegateCommand : AsyncCommand
    {
        private Action<object> _executeMethod;
        private string _text;
        public override string Text
        {
            get { return _text; }
        }

        protected override void OnExecute(object parameter)
        {
            _executeMethod(parameter);
        }

        public AsyncDelegateCommand(string name, Action<object> executeMethod)
        {
            _executeMethod = executeMethod;
            _text = name;
        }
    }

	public abstract class AsyncCommand : ICommand
	{
		public event EventHandler CanExecuteChanged;
		public event EventHandler Starting;
		public event RunWorkerCompletedEventHandler Completed;

		public abstract string Text { get; }

        public virtual string StartingMessage
        {
            get { return String.Format("Performing {0} ...", Text); }
        }

        public virtual string CompletedMessage
        {
            get { return String.Format("{0} successful.", Text); }
        }

	    public virtual string FailureMessageFormat
	    {
	        get { return String.Format("{0}  failed.", Text); }
	    }

	    private bool _isExecuting;
		public bool IsExecuting
		{
			get { return _isExecuting; }
			private set
			{
				_isExecuting = value;
				if (CanExecuteChanged != null)
					CanExecuteChanged(this, EventArgs.Empty);
			}
		}

		protected abstract void OnExecute(object parameter);

		public void Execute(object parameter)
		{	
			try
			{	
				onRunWorkerStarting();

			    var freezable = parameter as Freezable;
                if (freezable != null && !freezable.IsFrozen)
                    parameter = freezable.GetCurrentValueAsFrozen();

				var worker = new BackgroundWorker();
				worker.DoWork += ((sender, e) => OnExecute(e.Argument));
				worker.RunWorkerCompleted += ((sender, e) => onRunWorkerCompleted(e));
				worker.RunWorkerAsync(parameter);
			}
			catch (Exception ex)
			{
				onRunWorkerCompleted(new RunWorkerCompletedEventArgs(null, ex, true));
			}
		}

		private void onRunWorkerStarting()
		{
			IsExecuting = true;
			if (Starting != null)
				Starting(this, EventArgs.Empty);
		}

		private void onRunWorkerCompleted(RunWorkerCompletedEventArgs e)
		{
			IsExecuting = false;
			if (Completed != null)
				Completed(this, e);
		}

		public virtual bool CanExecute(object parameter)
		{
			return !IsExecuting;
		}
	}
}